package tcpClient

import (
	"errors"
	"fmt"
	"io"
	"net"
	"strconv"
	"time"
)

const OnStart string = "on_tcp_start"
const OnMessage string = "on_tcp_message"
const OnConnect string = "on_tcp_connect"
const OnDisConnect string = "on_tcp_disconnect"
const OnError string = "on_tcp_err"
const OnClose string = "on_tcp_close"

type TcpClient struct {
	eventMap  map[string][]interface{}
	debug     bool
	ipAddress string
	port      int
	con       net.Conn
	buffer    chan []byte
	isRun     bool
}

func (client *TcpClient) GetConn() net.Conn {
	return client.con
}
func (client *TcpClient) TryGetConn(sleepTime time.Duration, tryTimes int) (net.Conn, error) {
	if client.con != nil {
		return client.con, nil
	} else {
		timer := time.NewTicker(time.Millisecond * 50)
		tryTime := 0
		for true {
			select {
			case <-timer.C:
				tryTime++
				fmt.Println(tryTime, "尝试次数=====>")
				if client.con != nil {
					return client.con, nil
				}
				if tryTime > tryTimes {
					timer.Stop()
					return nil, errors.New("获取连接超时")
				}
			}
		}
		return nil, errors.New("获取连接超时")
	}
}
func (client *TcpClient) Connect(ipAddress string, port int, debug bool) {
	initClient(client)
	client.debug = debug
	/**
	执行绑定的client start函数
	*/
	if _, ok := client.eventMap[OnStart]; ok {
		for _, fun := range client.eventMap[OnStart] {
			go fun.(func())()
		}
		if debug {
			fmt.Println("开启调试模式:", "执行连接前的预处理")
		}
	}
	con, err := net.Dial("tcp", ipAddress+":"+strconv.Itoa(port))
	if err != nil {
		if _, ok := client.eventMap[OnError]; ok {
			for _, errFun := range client.eventMap[OnError] {
				go errFun.((func(err2 error)))(err)
			}
		}
		if debug {
			fmt.Errorf(err.Error())
		}
		return
	}
	if _, ok := client.eventMap[OnConnect]; ok {
		for _, fun := range client.eventMap[OnConnect] {
			go fun.((func(conn net.Conn)))(con)
		}
	}
	client.con = con
	go client.handler(con)
}
func (client *TcpClient) OnStart(fun func()) {
	initClient(client)
	client.eventMap[OnStart] = append(client.eventMap[OnStart], fun)
}
func (client *TcpClient) OnMessage(fun func(connection net.Conn, message []byte)) {
	initClient(client)
	client.eventMap[OnMessage] = append(client.eventMap[OnMessage], fun)
}

func (client *TcpClient) OnConnect(fun func(connection net.Conn)) {
	initClient(client)
	client.eventMap[OnConnect] = append(client.eventMap[OnConnect], fun)
}

func (client *TcpClient) OnDisConnect(fun func(connection net.Conn)) {
	initClient(client)
	client.eventMap[OnDisConnect] = append(client.eventMap[OnDisConnect], fun)
}
func (client *TcpClient) OnError(fun func(err error)) {
	initClient(client)
	client.eventMap[OnError] = append(client.eventMap[OnError], fun)
}
func (client *TcpClient) OnClose(fun func(conn net.Conn)) {
	initClient(client)
	client.eventMap[OnClose] = append(client.eventMap[OnClose], fun)
}
func (client *TcpClient) Close() {
	initClient(client)
	client.con.Close()
}
func initClient(client *TcpClient) {
	if client.eventMap == nil {
		client.eventMap = make(map[string][]interface{})
	}
}
func (client *TcpClient) handler(connection net.Conn) {
	initClient(client)
	client.buffer = make(chan []byte)
	client.isRun = true
	go func() {
		for client.isRun {
			data := <-client.buffer
			if _, ok := client.eventMap[OnMessage]; ok {
				messageFuns := client.eventMap[OnMessage]
				for _, messaheFun := range messageFuns {
					messaheFun = messaheFun
					messaheFun.(func(connection net.Conn, data []byte))(connection, data)
				}
			}
		}
		close(client.buffer)
	}()
	for true {
		data := make([]byte, 1024)
		n, err := connection.Read(data)
		if err != nil && err != io.EOF {
			if _, ok := client.eventMap[OnClose]; ok {
				closeFuns := client.eventMap[OnClose]
				if client.debug {
					fmt.Println("开启调试模式:", "连接被关闭=>"+connection.RemoteAddr().String())
				}
				for _, closeFun := range closeFuns {
					go closeFun.(func(conn net.Conn))(connection)
				}
			}
			if _, ok := client.eventMap[OnDisConnect]; ok {
				for _, disFun := range client.eventMap[OnDisConnect] {
					go disFun.(func(conn net.Conn))(connection)
				}
			}
			client.isRun = false
			break
		} else {
			if err != nil && err == io.EOF && n == 0 {
				if _, ok := client.eventMap[OnClose]; ok {
					closeFuns := client.eventMap[OnClose]
					if client.debug {
						fmt.Println("开启调试模式:", "连接被关闭=>"+connection.RemoteAddr().String())
					}
					for _, closeFun := range closeFuns {
						go closeFun.(func(conn net.Conn))(connection)
					}
				}
				if _, ok := client.eventMap[OnDisConnect]; ok {
					for _, disFun := range client.eventMap[OnDisConnect] {
						go disFun.(func(conn net.Conn))(connection)
					}
				}
				client.isRun = false
				break
			}
			data = data[:n]
			client.buffer <- data
		}
	}
}
